package com.bupt.basic;

import com.bupt.annotation.MParam;
import com.bupt.base.BaseDataSupport;
import com.bupt.dto.network.Node;
import com.bupt.exception.BaseException;
import com.bupt.utils.LinkStatusString;
import com.bupt.utils.excel.ExcelField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.*;

/**
 * 基础网络的一些公共属性定义
 *
 * @author 赵立刚 <zlgtop@163.com>
 * Created on 2021-03-17
 */
public interface IBasicNetWork {
    Logger log = LoggerFactory.getLogger(IBasicNetWork.class);
    // 层次信息
    LayerEnum[] layers = {LayerEnum.FIBER, LayerEnum.WDM, LayerEnum.OTN,
            LayerEnum.SDH};

    // 节点、链路
    // 当前的状况
    // 标志着是否可用
    @Getter
    enum Status {
        USING(0),// 使用中
        FORBID_USE(1), // 禁用
        DELETE(-1);// 删除
        private final Integer flag; // 标志

        Status(Integer tag) {
            this.flag = tag;
        }
    }

    // 网络的层次信息
    // 表示不同层次的网络
    @Getter
    enum LayerEnum {
        FIBER("FIBER"), WDM("WDM"), SDH("SDH"), OTN("OTN"),SATELLITE("SATELLITE"), SHORTWAVE("SHORTWAVE");
        private final String layer;
        private static final Map<String, LayerEnum> map = new HashMap<>();

        LayerEnum(String layer) {
            this.layer = layer;
        }

        static {
            for (LayerEnum layer : values()) { // values() 这个方法是 Java 编译后自动产生的
                if (null != map.put(layer.layer, layer)) {
                    throw new IllegalArgumentException("存在严重问题 layer 一样 启动失败");
                }
            }
        }

        public static LayerEnum getLayerEnum(String layer) throws BaseException {
            LayerEnum layerEnum = map.get(layer);
            if (null != layerEnum) return layerEnum;
            throw new BaseException("layer 应当为 FIBER、WDM、SDH、OTN、SATELLITE、SHORTWAVE");
        }
    }

    /**
     * 根据层次的信息 获取一个空白的链路
     *
     * @see #getBasicLinkByLayer(LayerEnum)
     */
    static BasicLink getBasicLinkByLayer(String layer) throws BaseException {
        return getBasicLinkByLayer(LayerEnum.getLayerEnum(layer));
    }

    /**
     * 根据层次的信息 获取一个空白的链路
     */
    static BasicLink getBasicLinkByLayer(@MParam("层次信息") LayerEnum layer) throws BaseException {
        // 根据不同的层次添加链路 更新链路
        switch (layer) {
            case FIBER: { // FiberLink
                return new FiberLink();
            }
            case WDM: { // WdmLink
                return new WdmLink();
            }
            case OTN: { // OTNLink
                return new OtnLink();
            }
            case SDH: { // SDHLink
                return new SdhLink();
            }

        }
        throw new BaseException("获取空白的失败");
    }

    // 更新属性的操作
    // 更新链路的属性
    // 设置成了一个 接口的默认的方法
    static void updateLinkFields(@MParam("目标链路") BasicLink targetLink, @MParam("链路洗洗") BasicLink link,
                                 @MParam("层次信息") LayerEnum layer) {
        // 更新公用的属性
        targetLink.code = link.code;
        targetLink.name = link.name;
        targetLink.label = link.label;
        targetLink.isOrigin = false; // 修改了 就不可能是原来的节点了
        targetLink.year = link.year;
        // 更新是否可用的标志
        targetLink.flag = link.flag;
        // 更细其他的信息
        targetLink.updateId = link.updateId;
        targetLink.updateName = link.updateName;
        targetLink.updateTime = link.updateTime;
        targetLink.status = link.status;
        targetLink.equipment = link.equipment;
        // 新增链路长度 每一个都会有链路长度的
        targetLink.length = link.length;
        // 根据不同的层次添加链路 更新链路
        switch (layer) {
            case FIBER: { // FiberLink
                FiberLink fiberLinkTarget = (FiberLink) targetLink;
                FiberLink linkSource = (FiberLink) link;
                fiberLinkTarget.xxsl = linkSource.xxsl;
                fiberLinkTarget.asfs = linkSource.asfs;
                fiberLinkTarget.glcd = linkSource.glcd;
                fiberLinkTarget.dy = linkSource.dy;
                fiberLinkTarget.whdw = linkSource.whdw;
                fiberLinkTarget.xxsh = linkSource.xxsh;
                fiberLinkTarget.glxh = linkSource.glxh;
                fiberLinkTarget.glqk = linkSource.glqk;
                // fixbug:fiber中服役年限、故障、损耗等属性无法修改（显示修改成功但刷新无变化）
                fiberLinkTarget.serviceLength = linkSource.serviceLength;
                fiberLinkTarget.faultTime = linkSource.faultTime;
                fiberLinkTarget.aveAttenua = linkSource.aveAttenua;
                break;
            }
            case WDM: { // WdmLink
                WdmLink wdmLink = (WdmLink) targetLink;
                WdmLink wdmLinkSource = (WdmLink) link;
                wdmLink.size = wdmLinkSource.size;
                wdmLink.rateStr = wdmLinkSource.rateStr;
                wdmLink.rate = BaseDataSupport.getRateByRateStr(wdmLinkSource.rateStr);
                wdmLink.loadOnLayer = wdmLinkSource.loadOnLayer;
                break;
            }
            case OTN: { // OTNLink
                OtnLink otnLink = (OtnLink) targetLink;
                OtnLink otnLinkSource = (OtnLink) link;
                otnLink.loadOnLayer = otnLinkSource.loadOnLayer;
                otnLink.size = otnLinkSource.size;
                otnLink.rateStr = otnLinkSource.rateStr;
                otnLink.rate = BaseDataSupport.getRateByRateStr(otnLinkSource.rateStr);
                break;
            }
            case SDH: { // SDHLink
                SdhLink sdhLink = (SdhLink) targetLink;
                SdhLink sdhLinkSource = (SdhLink) link;
                sdhLink.rateStr = sdhLinkSource.rateStr;
                sdhLink.loadOnLayer = sdhLinkSource.loadOnLayer;
                sdhLink.size = sdhLinkSource.size;
                sdhLink.rate = BaseDataSupport.getRateByRateStr(sdhLinkSource.rateStr);
                break;
            }

        } // end switch
    }

    // 节点的基本信息
    // 名称String name、代码String code、经度double longitude、维度double latitude、
    // 开通年份int year、竣工年份int completedYear、服役年限int serviceLength、类型（地区/军方）String areaType、
    // 当前容量int capacity、目标容量int targetCapacity、备品备件数int spareNum、当前备件数int currentNum
    // 、负责人（选填）String manager、联系方式（选填）String phone
    @Data
    final class BasicNode implements Serializable {
        private static final long serialVersionUID = 766472998823414247L;
        /*  基础属性  */
        @ExcelField(name = "节点ID", isMouldColumn = false)
        private String nodeId; // id
        //@ExcelField(name = "军区或地方", selectValues = {"军区", "地方"})
        private String over; // JQ DF
        @ExcelField(name = "节点名称")
        private String name; // 名字
        @ExcelField(name = "节点编码")
        private String code; // 代码
        @ExcelField(name = "经度")
        private Double pointX;// 经度
        @ExcelField(name = "纬度")
        private Double pointY;// 维度
        //@ExcelField(name = "是否核心节点", selectValues = {"核心节点", "非核心节点"})
        private String type; // 节点类型：是否为核心
        @JsonIgnore
        private String manager; // 责任人
        @JsonIgnore
        private String managerPhone; // 负责人电话
        //@ExcelField(name = "设备")
        private String equipment; // 设备（/正则表示）
        /*  其他的附加属性  */
        private Integer flag = Status.USING.flag;
        //        @ExcelField(name = "是否原始拓扑", selectValues = {"是", "否"})
        @JsonIgnore
        private Boolean isOrigin = false; // 是否属于原有拓扑 true or false
        @ExcelField(name = "开通年份")
        private Integer year;// 开通年份
        @ExcelField(name = "竣工年份")
        private Integer completedYear;
        @ExcelField(name = "服役年限")
        private Integer serviceLength;
        @ExcelField(name = "当前容量")
        private Integer capacity;
        @JsonIgnore
        private Integer targetCapacity;
        @JsonIgnore
        private Integer spareNum;
        @JsonIgnore
        private Integer currentNum;
        @JsonIgnore
        private String createId; // 创建者
        @JsonIgnore
        private String createName; // 创建者的名字
       // @ExcelField(name = "创建时间", isMouldColumn = false)
        @JsonIgnore
        private Date createDate; // 创建时间
        @JsonIgnore
        private String updateId; // 更新人ID
        @JsonIgnore
        private String updateName; // 名字
        @JsonIgnore
        private Date updateDate; // 更新时间
        @JsonIgnore
        private String area;  // 所属JQ
        @JsonIgnore
        private String jbz;



      /*  private List<DeviceManageComponent.NodeDevice> nodeDevices = new ArrayList<>();
        private String color = SystemColorEnum.BLACK.getColor(); // 颜色信息*/

        // 构造方法
        public BasicNode() {
        }

        public BasicNode(String nodeId,  String name, String code, Double pointX, Double pointY,
                          Integer year, Integer completedYear, Integer serviceLength, Integer capacity) {
            this.nodeId = nodeId;
            this.name = name;
            this.code = code;
            this.pointX = pointX;
            this.pointY = pointY;
            this.year = year;
            this.completedYear = completedYear;
            this.serviceLength = serviceLength;
            this.capacity = capacity;
        }

        // 更新自己操作
        public void updateSelf(BasicNode other) {
            this.nodeId = other.nodeId;
            this.name = other.name;
            this.code = other.code;
            this.pointX = other.pointX;
            this.pointY = other.pointY;
            // 是都删除的状态
            this.flag = other.flag;
            this.manager = other.manager;
            this.managerPhone = other.managerPhone;
            this.equipment = other.equipment;
            this.isOrigin = other.isOrigin;
            this.year = other.year;
            this.createId = other.createId;
            this.createName = other.createName;
            this.createDate = other.createDate;
            this.completedYear = other.completedYear;
            this.serviceLength = other.serviceLength;
            this.capacity = other.capacity;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof BasicNode)) return false;
            BasicNode basicNode = (BasicNode) o;
            return Objects.equals(getNodeId(), basicNode.getNodeId()) &&
                    Objects.equals(getOver(), basicNode.getOver()) &&
                    Objects.equals(getName(), basicNode.getName()) &&
                    Objects.equals(getCode(), basicNode.getCode()) &&
                    Objects.equals(getPointX(), basicNode.getPointX()) &&
                    Objects.equals(getPointY(), basicNode.getPointY()) &&
                    Objects.equals(getType(), basicNode.getType()) &&
                    Objects.equals(getManager(), basicNode.getManager()) &&
                    Objects.equals(getManagerPhone(), basicNode.getManagerPhone()) &&
                    Objects.equals(getEquipment(), basicNode.getEquipment()) &&
                    Objects.equals(getFlag(), basicNode.getFlag()) &&
                    Objects.equals(getIsOrigin(), basicNode.getIsOrigin()) &&
                    Objects.equals(getYear(), basicNode.getYear()) &&
                    Objects.equals(getCompletedYear(), basicNode.getCompletedYear()) &&
                    Objects.equals(getServiceLength(), basicNode.getServiceLength()) &&
                    Objects.equals(getCapacity(), basicNode.getCapacity()) &&
                    Objects.equals(getTargetCapacity(), basicNode.getTargetCapacity()) &&
                    Objects.equals(getSpareNum(), basicNode.getSpareNum()) &&
                    Objects.equals(getCurrentNum(), basicNode.getCurrentNum()) &&
                    Objects.equals(getCreateId(), basicNode.getCreateId()) &&
                    Objects.equals(getCreateName(), basicNode.getCreateName()) &&
                    Objects.equals(getCreateDate(), basicNode.getCreateDate()) &&
                    Objects.equals(getUpdateId(), basicNode.getUpdateId()) &&
                    Objects.equals(getUpdateName(), basicNode.getUpdateName()) &&
                    Objects.equals(getUpdateDate(), basicNode.getUpdateDate()) &&
                    Objects.equals(getArea(), basicNode.getArea()) &&
                    Objects.equals(getJbz(), basicNode.getJbz());
        }

        @Override
        public int hashCode() {
            return Objects.hash(getNodeId(), getOver(), getName(), getCode(), getPointX(), getPointY(),
                    getType(), getManager(), getManagerPhone(), getEquipment(), getFlag(), getIsOrigin(),
                    getYear(), getCompletedYear(), getServiceLength(), getCapacity(), getTargetCapacity(),
                    getSpareNum(), getCurrentNum(), getCreateId(), getCreateName(), getCreateDate(),
                    getUpdateId(), getUpdateName(), getUpdateDate(), getArea(), getJbz());
        }
    }

    // 上层链路的基本信息
    // 链路是互相承载的
    @EqualsAndHashCode
    @Data
    @AllArgsConstructor
    final class UpLevelMsg implements Serializable {
        private static final long serialVersionUID = -2062220049995539214L;
        private String level;
        private String linkId;
    }

    //端口类
    @EqualsAndHashCode
    @Data
    final class  Port implements  Serializable{
        private static final long serialVersionUID = -2062230049994539214L;
        private BasicNode node;//所属节点名字
        private Integer portNumber;//端口号

        public Port(BasicNode node, Integer portNumber) {
            this.node = node;
            this.portNumber = portNumber;
        }
    }
    @Data
    class PortL implements Serializable{
        private int id=0;
        private String type;
        private String status;
        private BasicLink link;
        public static int idCount=0;

        public PortL() {
        }
        public PortL( String type, String status, BasicLink link) {
            this.type = type;
            this.status = status;
            this.link = link;
            this.id=idCount++;
        }
    }

    // 链路的基本信息
    @Data
    abstract class BasicLink implements Serializable {
        private static final long serialVersionUID = -3514474399400836589L;
        /*   基础属性   */
        @ExcelField(name = "链路ID", isMouldColumn = false)
        private String id; // ID
        private String layer;// 所属层次
        @ExcelField(name = "链路编码")
        private String code; //代码
        @ExcelField(name = "链路名称")
        private String name; // name
        private String label; // 中文名称
        @ExcelField(name = "链路头节点", isExplored = false)
        private String nodeHead; //链头
        @ExcelField(name = "起始节点", isMouldColumn = false)
        private String nodeHeadName; //链头
        @ExcelField(name="头节点",isExplored = false,isMouldColumn = false)
        private Node sourceNode;//头节点
        @ExcelField(name = "链路尾节点", isExplored = false)
        private String nodeTail; // 链尾
        @ExcelField(name = "终止节点", isMouldColumn = false)
        private String nodeTailName; // 链尾
        //末节点
        @ExcelField(name="末节点",isExplored = false,isMouldColumn = false)
        private Node targetNode; //末节点
        @ExcelField(name = "链路长度（KM）")
        private Long length; // 链路长度
        private Boolean isOrigin = false; //是否属于原有拓扑 true or false 默认是不属于原有的拓扑的
        @ExcelField(name = "竣工年份")
        private Integer year;// 竣工年份 也就是服役时间
        /*  附加属性  */
        private Integer flag = Status.USING.getFlag(); // 是否删除 0：未删除；1：禁用；-1：删除 默认是 0 是可以用的
        @JsonIgnore
        private String createId;  // 创建者的ID
        @JsonIgnore
        private String createName;  // 名字
        @JsonIgnore
        private Date createTime;  // 创建时间
        @JsonIgnore
        private Boolean isValid;  //  zjt:判断是否链路可用于规划
        @JsonIgnore
        protected Double rate;  //  zjt:链路总带宽
        @JsonIgnore
        protected Double freeRate;  //  zjt:链路空闲带宽
        //private String color = SystemColorEnum.BLACK.getColor(); // 颜色信息
        @JsonIgnore
        private List<Port> usePortList=new ArrayList<>();
        private List<String> baseLinkIds=new ArrayList<>();
        private List<String> baseLinkNames=new ArrayList<>();
        private List<BasicLink> baseLinks=new ArrayList<>();
        public BasicLink() {
        }

        public BasicLink(String id, String layer, String code, String name, String label, String nodeHead,Node sourceNode,
                         String nodeTail,Node targetNode, Boolean isOrigin, Integer year, String createId,
                         String createName, Date createTime, Long length) {
            this.id = id;
            this.layer = layer;
            this.code = code;
            this.name = name;
            this.label = label;
            this.nodeHead = nodeHead;
            this.nodeTail = nodeTail;
            this.sourceNode=sourceNode;
            this.targetNode=targetNode;
            this.isOrigin = isOrigin;
            this.year = year;
            this.createId = createId;
            this.createName = createName;
            this.createTime = createTime;
            // 增加链路的长度
            this.length = length;
        }

        /*  其他的附加信息  */
        @JsonIgnore
        public List<UpLevelMsg> loadInLinkIds = new ArrayList<UpLevelMsg>(); // 承载了哪些的链路 上层的链路情况
        @JsonIgnore
        private List<String> loadOnLinksIds = new ArrayList<String>(); // 本层所使用的下层的路有的情况

        // 承载的fiber 物理 链路
        @JsonIgnore
        private Set<String> fiberLinkIdSet = new HashSet<>();
        // 业务的信息
        //@JsonIgnore
       private ServiceMsgOnLink serviceMsgOnLink;// 链路上承载的业务的信息情况

        // 给链路添加业务的操作
        public boolean addService(String pId, String pName, String demandUserName, DemandReportService service) throws BaseException {
            if (null == serviceMsgOnLink) this.serviceMsgOnLink = new ServiceMsgOnLink();
            this.serviceMsgOnLink.addServiceMsg(pId, pName, demandUserName, service);
            return true;
        }

        // 删除一个
        public void removeService(String serviceId) throws BaseException {
            if (null != serviceMsgOnLink) {
                this.serviceMsgOnLink.removeServiceMsg(serviceId);
            }
        }

        // 清理所有的信息
        public boolean clearAllService() throws BaseException {
            if (null == serviceMsgOnLink) this.serviceMsgOnLink = new ServiceMsgOnLink();
            this.serviceMsgOnLink.clear();
            return true;
        }

        // 获取所有的信息
        public List<ServiceMsgOnLink.ServiceMsg> getAllServiceMsg() {
            if (null == serviceMsgOnLink) this.serviceMsgOnLink = new ServiceMsgOnLink();
            return serviceMsgOnLink.getServiceMsgs();
        }

        @JsonIgnore
        private String updateId;  // 更新者ID
        @JsonIgnore
        private String updateName;  // 更新者名字
        @JsonIgnore
        private Date updateTime;  //时间
        @JsonIgnore
        private String status;  // 状态
        @JsonIgnore
        private String equipment;  // 设备（/正则表示）
        @JsonIgnore
        private String glgz;  //
        @JsonIgnore
        private String route;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof BasicLink)) return false;
            BasicLink basicLink = (BasicLink) o;
            return Objects.equals(getId(), basicLink.getId()) &&
                    Objects.equals(getLayer(), basicLink.getLayer()) &&
                    Objects.equals(getCode(), basicLink.getCode()) &&
                    Objects.equals(getName(), basicLink.getName()) &&
                    Objects.equals(getLabel(), basicLink.getLabel()) &&
                    Objects.equals(getNodeHead(), basicLink.getNodeHead()) &&
                    Objects.equals(getNodeHeadName(), basicLink.getNodeHeadName()) &&
                    Objects.equals(getNodeTail(), basicLink.getNodeTail()) &&
                    Objects.equals(getNodeTailName(), basicLink.getNodeTailName()) &&
                    Objects.equals(getLength(), basicLink.getLength()) &&
                    Objects.equals(getIsOrigin(), basicLink.getIsOrigin()) &&
                    Objects.equals(getYear(), basicLink.getYear()) &&
                    Objects.equals(getFlag(), basicLink.getFlag()) &&
                    Objects.equals(getCreateId(), basicLink.getCreateId()) &&
                    Objects.equals(getCreateName(), basicLink.getCreateName()) &&
                    Objects.equals(getCreateTime(), basicLink.getCreateTime()) &&
                    Objects.equals(getIsValid(), basicLink.getIsValid()) &&
                    Objects.equals(getRate(), basicLink.getRate()) &&
                    Objects.equals(getFreeRate(), basicLink.getFreeRate());
        }

        @Override
        public int hashCode() {
            return Objects.hash(getId(), getLayer(), getCode(), getName(), getLabel(), getNodeHead(),
                    getNodeHeadName(), getNodeTail(), getNodeTailName(), getLength(), getIsOrigin(),
                    getYear(), getFlag(), getCreateId(), getCreateName(), getCreateTime(),
                    getIsValid(), getRate(), getFreeRate());
        }
    }// end BasicLink

    public interface HaveTraffic {
        //进行具体子粒度承载工作
        boolean addTrafficWork(Double serviceRate);

        Integer addWDMTrafficWork(Double serviceRate);

        //判断是否有足够子粒度能承载
        boolean canAdd(Double serviceRate);

        //子粒度资源释放
        void releaseZLD();
    }

    // 波道
    @Data
    public static final class WaveChannel implements Serializable {
        private static final long serialVersionUID = 2304390089609116923L;
        private String status = LinkStatusString.FREE;//波道使用状态 空闲,工作,保护,恢复;
        private Double rate;

        public WaveChannel(String status, Double rate) {
            this.status = status;
            this.rate = rate;
        }
    }

    @Data
    public static final class OTU implements Serializable {
        private static final long serialVersionUID = -6624703047717656062L;
        private String status = LinkStatusString.FREE;//波道使用状态 空闲,工作,保护,恢复;
        private Double rate;

        public OTU(String status, Double rate) {
            this.status = status;
            this.rate = rate;
        }
    }

    @Data
    public static final class TimeSlot implements Serializable {
        private static final long serialVersionUID = -176998126820914407L;
        private String status = LinkStatusString.FREE;//波道使用状态 空闲,工作,保护,恢复;
        private Double rate;

        public TimeSlot(String status, Double rate) {
            this.status = status;
            this.rate = rate;
        }
    }

    // 光纤链路
    @Data
    final class FiberLink extends BasicLink {
        private static final long serialVersionUID = -4059722097572965001L;
        @ExcelField(name = "纤芯数量")
        private Long xxsl;   // 纤芯数量
        @ExcelField(name = "敷设方式", selectValues = {"空缆", "地缆", "海缆"})
        private String asfs; // 敷设方式
        @ExcelField(name = "光缆长度（KM）")
        private Long glcd;   // 光缆长度 单位 km
        //@ExcelField(name = "地域")
        @JsonIgnore
        private String dy;  // 地域
        //@ExcelField(name = "维护单位", selectValues = {"中国电信", "中国联通", "中国移动", "广电", "军队自维"})
        private String whdw; // 维护单位
        @ExcelField(name = "纤芯衰耗")
        private Double xxsh;  // 纤芯衰耗
        //@ExcelField(name = "光缆型号")
        @JsonIgnore
        private String glxh;  // 光缆型号
        //@ExcelField(name = "光缆情况")
        @JsonIgnore
        private String glqk;  // 光缆情况
        @ExcelField(name = "服役年限")
        private Integer serviceLength;
        @ExcelField(name = "平均每年故障时间")
        private Integer faultTime;
        @ExcelField(name = "平均衰耗")
        private Double aveAttenua;

        public FiberLink() {
        }

        /* 下面是 基本的构造方法  */
        public FiberLink(String linkId, String layer, String code, String linkName, String label, String nodeHead,Node fromNode,
                         String nodeTail,Node toNode,Boolean isOrigin, Integer year, String createId, String createName,
                         Date createTime, Long xxsl, String asfs, Long glcd, String dy, String whdw,
                         Double xxsh, String glxh, String glqk, Long length, Integer serviceLength, Integer faultTime, Double aveAttenua) {
            super(linkId, layer, code, linkName, label, nodeHead,fromNode, nodeTail,toNode, isOrigin, year, createId, createName,
                    createTime, length);
            this.xxsl = xxsl;
            this.asfs = asfs;
            this.glcd = glcd;
            this.dy = dy;
            this.whdw = whdw;
            this.xxsh = xxsh;
            this.glxh = glxh;
            this.glqk = glqk;
            this.serviceLength = serviceLength;
            this.faultTime = faultTime;
            this.aveAttenua = aveAttenua;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof FiberLink)) return false;
            if (!super.equals(o)) return false;
            FiberLink fiberLink = (FiberLink) o;
            return Objects.equals(getXxsl(), fiberLink.getXxsl()) &&
                    Objects.equals(getAsfs(), fiberLink.getAsfs()) &&
                    Objects.equals(getGlcd(), fiberLink.getGlcd()) &&
                    Objects.equals(getDy(), fiberLink.getDy()) &&
                    Objects.equals(getWhdw(), fiberLink.getWhdw()) &&
                    Objects.equals(getXxsh(), fiberLink.getXxsh()) &&
                    Objects.equals(getGlxh(), fiberLink.getGlxh()) &&
                    Objects.equals(getGlqk(), fiberLink.getGlqk()) &&
                    Objects.equals(getServiceLength(), fiberLink.getServiceLength()) &&
                    Objects.equals(getFaultTime(), fiberLink.getFaultTime()) &&
                    Objects.equals(getAveAttenua(), fiberLink.getAveAttenua());
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), getXxsl(), getAsfs(), getGlcd(), getDy(),
                    getWhdw(), getXxsh(), getGlxh(), getGlqk(), getServiceLength(), getFaultTime(), getAveAttenua());
        }
    }

    @Data
    final class WdmLink extends BasicLink implements HaveTraffic {
        private static final long serialVersionUID = 6009818287183649033L;
        @ExcelField(name = "配置波道数")
        private Long size; // 配置波道数
        @ExcelField(name = "线路速率", selectValues = {"GE", "2.5G", "10G", "100G"})
        private String rateStr;
        // 波道的信息
        @JsonIgnore
        private List<WaveChannel> waveChannels = new ArrayList<>();
        @JsonIgnore
        private String loadOnLayer; // 承载层

        @JsonIgnore
        private List<BasicLink> layerRouteLinkList;

        public void setSize(Long size) {
            this.size = size;
            if (null == this.waveChannels) this.waveChannels = new ArrayList<>();
            Double rateByRateStr = BaseDataSupport.getRateByRateStr(rateStr);
            if (null != rateByRateStr) {
                this.waveChannels.clear();
                for (int i = 0; i < size; i++) {
                    this.waveChannels.add(new WaveChannel(LinkStatusString.FREE, rateByRateStr));
                }
            }
        }
        public List<BasicLink> takeLayerRouteLinkList() {
            return this.layerRouteLinkList;
        }

        public void setRateStr(String rateStr) {
            this.rateStr = rateStr;
            // 设置速率
            this.rate = BaseDataSupport.getRateByRateStr(rateStr);
            this.freeRate = rate;
        }

        @Override
        public boolean canAdd(Double rate) {
            if (rate == null) {
                return false;
            }
            //有剩余波道数
            for (WaveChannel waveChannel : this.waveChannels) {
                if (waveChannel.getStatus().equals(LinkStatusString.FREE) && waveChannel.getRate() >= rate) {
                    //有一个即可
                    return true;
                }
            }

            return false;
        }

        @Override
        public boolean addTrafficWork(Double service) {
            return true;
        }

        @Override
        public Integer addWDMTrafficWork(Double serviceRate) {
            int waveLengthNum = 0;
            if (canAdd(serviceRate)) {
                for (WaveChannel waveChannel : waveChannels) {
                    if (waveChannel.getStatus().equals(LinkStatusString.FREE) && waveChannel.getRate() >= rate) {
                        waveChannel.setStatus(LinkStatusString.WORK);
                        return waveLengthNum;
                    }
                    waveLengthNum++;
                }
            }
            return null;
        }

        @Override
        public void releaseZLD() {
            for (WaveChannel waveChannel : waveChannels) {
                waveChannel.setStatus(LinkStatusString.FREE);
            }
            this.freeRate = this.rate;
        }

        public WdmLink() {
        }

        public WdmLink(String linkId, String layer, String code, String linkName, String label,String nodeHead,Node fromNode,
                       String nodeTail,Node toNode, Boolean isOrigin, Integer year, String createId, String createName,
                       Date createTime, Long size, String rateStr, String loadOnLayer, Long length) {
            super(linkId, layer, code, linkName, label, nodeHead,fromNode, nodeTail,toNode, isOrigin, year, createId,
                    createName, createTime, length);
            this.size = size;
            this.rateStr = rateStr;
            this.rate = BaseDataSupport.getRateByRateStr(rateStr);
            this.loadOnLayer = loadOnLayer;
            this.freeRate = rate;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof WdmLink)) return false;
            if (!super.equals(o)) return false;
            WdmLink wdmLink = (WdmLink) o;
            return Objects.equals(getSize(), wdmLink.getSize()) &&
                    Objects.equals(getRateStr(), wdmLink.getRateStr()) &&
                    Objects.equals(getWaveChannels(), wdmLink.getWaveChannels()) &&
                    Objects.equals(getLoadOnLayer(), wdmLink.getLoadOnLayer());
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), getSize(), getRateStr(), getWaveChannels(), getLoadOnLayer());
        }
    }

    // otn的link
    @Data
    final class OtnLink extends BasicLink implements HaveTraffic {
        private static final long serialVersionUID = 3622131141337784261L;
        @ExcelField(name = "承载层", selectValues = {"FIBER", "WDM"})
        private String loadOnLayer; // 承载层
        //@ExcelField(name = "配置光网络单元数")
        @JsonIgnore
        private Long size;// 光网络传输单元数目
        @ExcelField(name = "线路速率", selectValues = {"GE", "2.5G", "10G", "100G"})
        private String rateStr;
        @JsonIgnore
        private List<OTU> otus = new ArrayList<>();

        @JsonIgnore
        private List<BasicLink> layerRouteLinkList;

        public void setSize(Long size) {
            this.size = size;
            Double rateByRateStr = BaseDataSupport.getRateByRateStr(rateStr);
            if (null == this.otus) this.otus = new ArrayList<>();
            if (null != rateByRateStr) {
                this.otus.clear();
                for (int i = 0; i < size; i++) {
                    this.otus.add(new OTU(LinkStatusString.FREE, rateByRateStr));
                }
            }
        }

        public List<BasicLink> takeLayerRouteLinkList() {
            return this.layerRouteLinkList;
        }


        public void setRateStr(String rateStr) {
            this.rateStr = rateStr;
            // 设置速率
            this.rate = BaseDataSupport.getRateByRateStr(rateStr);
            this.freeRate = rate;
        }

        @Override
        public boolean canAdd(Double rate) {
            if (rate == null) {
                return false;
            }
            return freeRate >= rate;
        }

        @Override
        public boolean addTrafficWork(Double serviceRate) {
            //若当前链路可以承载此业务（空闲速率大于业务速率）
            if (canAdd(serviceRate)) {
                double trafficRate = serviceRate;
                for (OTU otu : this.otus) {
                    if (trafficRate > 0) {
                        if (otu.getStatus().equals(LinkStatusString.FREE)) {
                            otu.setStatus(LinkStatusString.WORK);
                            trafficRate = trafficRate - otu.getRate();
                            this.freeRate = this.freeRate - otu.getRate();
                        }
                        //若此otu状态不为空闲，即跳转到下一个otu判断
                        else {
                            continue;
                        }
                    }
                    //需要承载的链路速率不大于零（不用再承载），即退出otu循环
                    else {
                        break;
                    }
                }
                return true;
            }
            return false;
        }

        @Override
        public Integer addWDMTrafficWork(Double serviceRate) {
            return null;
        }

        @Override
        public void releaseZLD() {
            for (OTU otu : this.otus) {
                otu.setStatus(LinkStatusString.FREE);
            }
            this.freeRate = this.rate;
        }

        public OtnLink() {
        }

        public OtnLink(String linkId, String layer, String code, String linkName, String label,String nodeHead,Node fromNode,
                       String nodeTail,Node toNode,Boolean isOrigin, Integer year, String createId, String createName,
                       Date createTime, String loadOnLayer, Long size, String rateStr, Long length) {
            super(linkId, layer, code, linkName, label, nodeHead,fromNode, nodeTail, toNode,isOrigin, year, createId,
                    createName, createTime, length);
            this.loadOnLayer = loadOnLayer;
            this.size = size;
            this.rateStr = rateStr;
            // 设置速率
            this.rate = BaseDataSupport.getRateByRateStr(rateStr);
            this.freeRate = rate;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof OtnLink)) return false;
            if (!super.equals(o)) return false;
            OtnLink otnLink = (OtnLink) o;
            return Objects.equals(getLoadOnLayer(), otnLink.getLoadOnLayer()) &&
                    Objects.equals(getSize(), otnLink.getSize()) &&
                    Objects.equals(getRateStr(), otnLink.getRateStr());
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), getLoadOnLayer(), getSize(), getRateStr());
        }
    }

    @Data
    final class SdhLink extends BasicLink implements HaveTraffic {
        private static final long serialVersionUID = -59722107268698910L;
        @ExcelField(name = "承载层", selectValues = {"FIBER","WDM", "OTN"})
        private String loadOnLayer; // 承载层
        @JsonIgnore
        //@ExcelField(name = "时隙数目")
        private Long size;// 时隙数目
        @ExcelField(name = "线路速率", selectValues = {"155M", "622M", "GE", "2.5G", "10G", "100G"})
        private String rateStr;  // 线路速率(G)
        @JsonIgnore
        private List<TimeSlot> timeSlots = new ArrayList<>();

        @JsonIgnore
        private List<BasicLink> layerRouteLinkList;

        public void setSize(Long size) {
            this.size = size;
            if (null == this.timeSlots) this.timeSlots = new ArrayList<>();
            Double rateByRateStr = BaseDataSupport.getRateByRateStr(rateStr);
            if (null != rateByRateStr) {
                this.timeSlots.clear();
                for (int i = 0; i < size; i++) {
                    this.timeSlots.add(new TimeSlot(LinkStatusString.FREE, rateByRateStr));
                }
            }
        }
        public List<BasicLink> takeLayerRouteLinkList() {
            return this.layerRouteLinkList;
        }


        public void setRateStr(String rateStr) {
            // 设置速率
            this.rateStr = rateStr;
            this.rate = BaseDataSupport.getRateByRateStr(rateStr);
            this.freeRate = rate;
        }

        @Override
        public boolean canAdd(Double rate) {
            if (rate == null) {
                return false;
            }
            if (freeRate >= rate) {

                return true;
            }
            return false;
        }

        @Override
        public boolean addTrafficWork(Double serviceRate) {
            //若当前链路可以承载此业务（空闲速率大于业务速率）
            if (canAdd(serviceRate)) {
                double trafficRate = serviceRate;
                for (TimeSlot timeSlot : this.timeSlots) {
                    if (trafficRate > 0) {
                        if (timeSlot.getStatus().equals(LinkStatusString.FREE)) {
                            timeSlot.setStatus(LinkStatusString.WORK);
                            trafficRate = trafficRate - timeSlot.getRate();
                            this.freeRate = this.freeRate - timeSlot.getRate();
                        }
                        //若此timeSlot状态不为空闲，即跳转到下一个timeSlot判断
                        else {
                            continue;
                        }
                    }
                    //需要承载的链路速率不大于零（不用再承载），即退出timeSlot循环
                    else {
                        break;
                    }
                }
                return true;
            }
            return false;
        }

        @Override
        public Integer addWDMTrafficWork(Double serviceRate) {
            return null;
        }

        @Override
        public void releaseZLD() {
            for (TimeSlot timeSlot : this.timeSlots) {
                timeSlot.setStatus(LinkStatusString.FREE);
            }
            this.freeRate = this.rate;
        }

        public SdhLink() {
        }

        public SdhLink(String linkId, String layer, String code, String linkName, String label, String nodeHead,Node fromNode,
                       String nodeTail,Node toNode, Boolean isOrigin, Integer year, String createId, String createName,
                       Date createTime, String rateStr, String loadOnLayer, Long size, Long length) {
            super(linkId, layer, code, linkName, label, nodeHead,fromNode, nodeTail,toNode, isOrigin, year, createId,
                    createName, createTime, length);
            this.rateStr = rateStr;
            this.loadOnLayer = loadOnLayer;
            this.size = size;
            this.rate = BaseDataSupport.getRateByRateStr(rateStr);
            this.freeRate = rate;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof SdhLink)) return false;
            if (!super.equals(o)) return false;
            SdhLink sdhLink = (SdhLink) o;
            return Objects.equals(getLoadOnLayer(), sdhLink.getLoadOnLayer()) &&
                    Objects.equals(getSize(), sdhLink.getSize()) &&
                    Objects.equals(getRateStr(), sdhLink.getRateStr());
        }

        @Override
        public int hashCode() {
            return Objects.hash(super.hashCode(), getLoadOnLayer(), getSize(), getRateStr());
        }
    }


}
